pp108 : Creating a Composite Control using Existing XForms Controls

Creating a Composite Control using Existing XForms Controls

This topic describes the procedure to create a composite control by using an existing XForm control.

The composite control framework enables you to use the controls available in the XForms Designer and create a composite control using them.

If your composite control comprises a group of controls, you must always use a grouping control (the Groupbox, TabGroup, Group, or Table control) as the parent control, while designing the composite control.

Consider creating a Effective Interest Calculator control that combines multiple XForms controls and, at run time, provides you with an output based on the values you provide. This composite control calculates the effective annual interest rate based on a given nominal interest rate and the number of times it is compounded annually. You will be able to specify the nominal interest rate and number of compounding periods at run time.

  1. Open a new XForm and design the interface of the control in the XForms Designer. Change the label of each control as given below. Also, modify the ID and Tooltipin the property sheet of each control.

    Control

    Change label to

    Change id to

    Add tooltip text

    Groupbox

    Effective Interest Calculator

    -

    -

    Input

    Annual Interest Rate

    interestRate

    Enter the annual interest rate

    Input

    Number of Compounding Periods

    compoundingPeriods

    Enter the number of compounding periods

    Button

    Calculate Effective Interest Rate

    calculatebtn

    Click to calculate effective annual interest rate

    Output

    Effective Annual Interest Rate

    effectiveRate

    Effective annual interest rate


    The interface of the control is modified as shown below.

  2. Right-click the Groupbox control and select Save as Composite Control. The UntitledCompositeControl.Htm dialog box appears, where you can provide details regarding the design-time library of the composite control.
  3. Make appropriate modifications in the UntitledCompositeControl.Htm dialog box.
    • Type the name of the design-time library in the Name field. In this case, you can name the design-time library as
      EffectiveInterestCalculator.
    • Type a description for the design-time library in the Description field.
    • In the Location field, select and specify the location at which the library must be saved in the Select Folder dialog box that displays. The title of the dialog box changes to <design-time library name>.Htm.
  4. Click Save. The Untitled Composite Control - Composite Control wizard appears. The design-time library, created above, displays in the Design Time Library field.
  5. Make appropriate modifications in the Untitled Composite Control - Composite Control wizard.
    • Type the name of the composite control in the Name field.
    • Type a description for the composite control in the Description field.
    • Select the ControlControl Type option to provide the design-time and run-time libraries based on which the composite control must be created. This option is selected by default.


      Note: The REST URL Control Type option is used to create URL-based composite control.


      The title of the wizard changes to <composite control> - Composite Control.

  6. In the Design Time Library field, click to view the code generated for the design-time library.
    Note: Alternately, click to specify another existing design-time library from the Select Design Time Library dialog box that displays. The <design-time library>.htm - Htmdialog box displays the following auto-generated code.
    <!-- EffectiveInterestCalculator design time control --> <html><head> <script type="text/javascript"> //retain the setPublic() method as shown for your composite control setPublic(EffectiveInterestCalculator1, "designtimeLibrary"); //provide the namespace of the group element as defined in the wcpforms:designLibrary attribute in the markup of your composite control importType("cas.xforms.designerlibrary.controls.XFormsGroupbox"); //provide the group element from which this composite control is inherited inherit(EffectiveInterestCalculator1, XFormsGroupbox); //inherit(); EffectiveInterestCalculator1.icon = "/cordys/wcp/theme/default/icon/document/compositecontrol.png"; // This is the constructor of the composite control // It calls the base class's constructor function EffectiveInterestCalculator1(designerView) { this.XFormsControl(designerView); } </script> <script xmlns="http://www.w3.org/2002/xforms/cr" type="cordys/xml" id="_controlDefinition" > <xforms:group xmlns:xforms="http://www.w3.org/2002/xforms/cr" appearance="box" wcpforms:designLibrary="cas.xforms.designerlibrary.controls.XFormsGroupbox" xmlns:wcpforms="http://schemas.cordys.com/wcp/xforms" wcpforms:layout="vertical" wcpforms:class="v_layout" wcpforms:size="null null" wcpforms:labelalign="ontop" > <xforms:label wcpforms:class="groupheader" >Effective Interest Calculator</xforms:label> <xforms:input wcpforms:designLibrary="cas.xforms.designerlibrary.controls.XFormsInput" id="interestRate" doEBIValidate="false" wcpforms:class="v_layout" > <xforms:label wcpforms:class="v_label" >Annual Interest Rate</xforms:label> <xforms:hint>Enter the annual interest rate</xforms:hint> </xforms:input> <xforms:input wcpforms:designLibrary="cas.xforms.designerlibrary.controls.XFormsInput" id="compoundingPeriods" doEBIValidate="false" wcpforms:class="v_layout" > <xforms:label wcpforms:class="v_label" >Number of compounding periods</xforms:label> <xforms:hint>Enter the number of compounding periods</xforms:hint> </xforms:input> <xforms:group appearance="controlbox" wcpforms:designLibrary="cas.xforms.designerlibrary.controls.XFormsControlbox" id="controlbox1" controltype="button" wcpforms:layout="horizontal" wcpforms:class="v_layout" wcpforms:align="center_align" wcpforms:size="null auto" > <xforms:trigger wcpforms:designLibrary="cas.xforms.designerlibrary.controls.XFormsButton" id="calculatebtn" wcpforms:class="h_button" wcpforms:size="230px 2em" > <xforms:label>Calculate Effective Interest Rate</xforms:label> <xforms:hint>Click to calculate effective annual interest rate</xforms:hint> </xforms:trigger> </xforms:group> <xforms:output wcpforms:designLibrary="cas.xforms.designerlibrary.controls.XFormsOutput" id="effectiveRate" doEBIValidate="false" wcpforms:class="v_layout" > <xforms:label wcpforms:class="v_label" >Effective Annual Interest Rate</xforms:label> <xforms:hint>Effective annual interest rate</xforms:hint> </xforms:output> </xforms:group> </script> </head><body></body></html>

    The code contains markup of the interface designed for the Effective Interest Calculator control. In the above design-time composite control:


    • The setPublic() method gives the path where the control is saved (in below example, it's design-time Library). This may vary in case of your composite control. While using the below code to create your own composite control, ensure that the code that is auto-generated for setPublic() method is retained.
    • The namespace of the group element is provided in the importType() method as defined in the wcpforms:designLibrary attribute in the markup of your composite control. For example, in this case, the value of the wcpforms:designLibrary attribute is cas.xforms.designerlibrary.controls.XFormsGroupbox.
    • In the inherit() method, the group element from which your control is inherited is provided, as specified in the wcpforms:designLibrary attribute in the markup. For example, in this case, the group element is XForms Group box.
  7. In the Run Time Library field, click to create a run-time library and click Yes in the Confirm dialog box that displays.
    Note: Alternately, click to specify an existing run-time library from the Select Run Time Library dialog box that displays. The <run-time library>.htm - Htm dialog box displays.
  8. Make appropriate modifications in the <run-time library>.htm - Htm dialog box.
    • Type the name of the run-time library in the Name field. In this case, you can name the run-time library as
      EffectiveInterestCalculator.
    • Type a description for the run-time library in the Description field.
    • In the Location field, select and specify the location at which the library must be saved in the Select Folder dialog box that displays. The <run-time library>.htm - Htm dialog box displays the standard code structure using which you can build your run-time library.
  9. Add the following code to create a run-time library for the Effective Interest Calculator control. In the below example, the setPublic() method gives the path where the control is saved (in below example its runtimeLibrary). This may vary in case of your composite control. While using the below code to create your own composite control, ensure that the code that is auto-generated for setPublic() method is retained.
    <!-- EffectiveInterestCalculator runtime control --> <html><head> <script type="text/javascript"> setPublic(EffectiveInterestCalculator, "runtimeLibrary"); importType("cas.xforms.runtimelibrary.CompositeControl"); importType("cas.xforms.runtimelibrary.ContainerElement"); inherit(EffectiveInterestCalculator, CompositeControl); inherit(EffectiveInterestCalculator, ContainerElement); function EffectiveInterestCalculator() { } function EffectiveInterestCalculator.attachType( control ) { // Mandatory // Call the attachType of superClass. application.addType(control, "cas.xforms.runtimelibrary.ContainerElement"); // Store the references of controls inside the Effective Interest Calculator control. // Attach event handlers as required. control.interestRate = control.getElementById("interestRate"); control.interestRate.onblur = validateFieldValue(control.interestRate, control); control.compoundingPeriods = control.getElementById("compoundingPeriods"); control.compoundingPeriods.onblur = validateFieldValue(control.compoundingPeriods, control); control.calculatebtn = control.getElementById("calculatebtn"); control.calculatebtn.onclick = calculateInterestRate(control); control.effectiveRate = control.getElementById("effectiveRate"); } function EffectiveInterestCalculator.detachType( control ) { // Mandatory // Call the detachType method of the superClass. application.removeType( control, "cas.xforms.runtimelibrary.ContainerElement"); // Clear all the instance variables control.interestRate = null; control.compoundingPeriods = null; control.calculatebtn = null; control.effectiveRate = null; } function validateFieldValue(htmlElem, effectiveinterestcalculator) { return function() { var value = parseFloat(htmlElem.value); // If value of the field is not a number or 0, put a effectiveRate. if (isNaN(value) || value == 0) { effectiveinterestcalculator.getApplication().notify("Enter valid value."); } } } function calculateInterestRate(effectiveinterestcalculator) { return function() { // Parse the specified values var interestRate = parseFloat(effectiveinterestcalculator.interestRate.value); var compoundingPeriods = parseFloat(effectiveinterestcalculator.compoundingPeriods.value); var resultField = effectiveinterestcalculator.effectiveRate; var errorMsg = ""; if(isNaN(interestRate) || isNaN(compoundingPeriods)) errorMsg = "Enter numeric values"; else if(interestRate <= 0) errorMsg = "Enter valid annual interest rate"; else if(compoundingPeriods < 1) errorMsg = "Enter valid number for compounding periods"; if(errorMsg) { effectiveinterestcalculator.getApplication().showError(errorMsg); return; } // Calculate the effective interest and round it off to 2 decimal places. var result = 1 + (interestRate/compoundingPeriods); result = new Number(Math.pow(result, compoundingPeriods) - 1); result = result.toPrecision(4); effectiveinterestcalculator.effectiveRate.value = result; } } </script> </head><body></body></html>

    Note that since the Effective Interest Calculator control is essentially a grouping control (in this case, a Groupbox control), it needs to extend from the Container Element library, which is a run-time representation of all the grouping controls. This is done using the importType and inherit statements in the above code.
    By doing this, the getElementById() Web service operation of the container Element library can be used to access individual controls within the Groupbox.

  10. Click in the <composite control> - Composite Control dialog box. The composite control is created. The Effective Interest Calculator composite control is now ready for use. You can enter values in the control at run time, and calculate the effective interest rate.
    Both the composite control and the design-time library of the composite control display in the Workspace Documents window. You can drag the composite control to an XForm to use it. Alternately, you can right-click the XForm, select Insert Composite Control, and drag the composite control from the Composite Controls dialog box that displays. This right-click menu option is available for a split area, an XForm, and for the Group, Groupbox, and Tab Page grouping controls.
    Note: You can delete the composite control from the Workspace Documents window. This does not automatically delete the design-time library associated with the control, enabling you to reuse the design-time library with other composite controls.
    Note: Process Platform is now multiple browser compliant. For composite controls created in BOP-4 GA that are now ported to Cordys BOP 4.1 and need to be made multiple browser compliant, you must ensure multiple browser support for the same.
  • If no custom modifications were made to the design-time and runtime libraries of the composite control, you can delete the libraries and generate new ones in Cordys BOP 4.1.
  • If you had made custom modifications to the design-time and runtime libraries of the composite control, you must manually provide custom script for multiple browser support. For details, refer to Enabling Multi-browser Support for Web Content.